package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.PowerManager;
import android.util.Log;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "NATClient";
    private NatThread mThread = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG,"onStart");
        boolean rc = requestPermissions();
        checkBatteryOptimizations();
        if (rc && mThread == null) {
            mThread = new NatThread(getApplicationContext());
            mThread.start();
        }
    }

    @Override
    protected void onDestroy() {
        Log.d(TAG,"onDestroy");
        if( mThread != null ) {
            mThread.interrupt();
            mThread = null;
        }
        super.onDestroy();
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if( requestCode != 816 ) return;

        // start anyway
        if( mThread == null ) {
            mThread = new NatThread(getApplicationContext());
            mThread.start();
        }
    }

    public boolean requestPermissions() {
        String[] permissions = {
                "android.permission.INTERNET",
                "android.permission.WAKE_LOCK",
                "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS",
        };
        List<String> permissionList = new ArrayList<>();
        for (String permission : permissions) {
            if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
                Log.d(TAG,"has no permission " + permission);
                permissionList.add(permission);
            }
        }

        if( permissionList.isEmpty() ) {
            return true;
        } else {
            String[] permissionsArray = permissionList.toArray(new String[0]);//将List转为数组
            ActivityCompat.requestPermissions(this, permissionsArray, 816);
            return false;
        }
    }

    public void checkBatteryOptimizations() {
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            String packageName = getPackageName();
            PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
            if (!pm.isIgnoringBatteryOptimizations(packageName)) {
                Log.d(TAG, packageName + " not in battery optimization white list");
                Intent intent = new Intent();
                intent.setAction(android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
                intent.setData(Uri.parse("package:" + packageName));
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(intent);
            } else  {
                Log.d(TAG, packageName + " already in battery optimization white list");
            }
        }
    }

    static private class NatThread extends Thread {
        private final Context mContext;

        public NatThread(Context context) {
            mContext = context;
        }
        @Override
        public void run() {
            DatagramSocket sock = null;
            PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
            PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "NATClient::wl");

            wakeLock.acquire(15*60*1000);
            try {

                sock = new DatagramSocket();
                InetSocketAddress address = new InetSocketAddress("47.88.158.73",7777);
                String command = "START";
                byte[] data = command.getBytes(Charset.forName("UTF-8"));
                DatagramPacket packet = new DatagramPacket(data,data.length,address);
                sock.send(packet);
                Log.d(TAG,"send START");

                do {
                    byte[] recv_buffer = new byte[1024];
                    packet = new DatagramPacket(recv_buffer,recv_buffer.length);
                    sock.receive(packet);
                    if( packet.getData() != null ) {
                        Log.d(TAG,"recv " + packet.getLength() + " bytes");
                        sock.send(packet);
                    }
                } while( ! isInterrupted() );
            } catch (SocketException e) {
                e.printStackTrace();
                Log.e(TAG,"SocketException");
            } catch (IOException e) {
                e.printStackTrace();
                Log.e(TAG,"IOException");
            } finally {
                if( sock != null ) {
                    sock.close();
                }
                if (wakeLock.isHeld()) {
                    Log.d(TAG,"release wakelock");
                    wakeLock.release();
                }
                wakeLock = null;
            }
        }
    }
}